<template>
    <el-tree ref="treeRef" :data="data" :node-key="nodeKey" show-checkbox :props="props" :check-strictly="true"
        @check="onCheck" />
</template>

<script setup lang="ts">
import { ElTree } from 'element-plus';
import { ref } from 'vue';
// 引入图标
import * as icons from '@element-plus/icons-vue';
const treeRef = ref<InstanceType<typeof ElTree>>();
// 定义每一个菜单对象的类型（可以直接用全局定义的）
interface MenuItem {
    _id: string;
    title: string;
    children?: MenuItem[];
    icon?: keyof (typeof icons);
    path: string;
    pid: string;
}

// 接收父组件传递的数据
const { data = [], nodeKey = '_id', props = { label: 'title' } } = defineProps<{
    data: any[],
    nodeKey?: string,
    props?: object
}>()

// 点击tree中复选框时触发的事件
const onCheck = (data: MenuItem, { checkedKeys }: { checkedKeys: string[] }) => {
    if (checkedKeys.includes(data._id)) {
        // 设置选中
        setChecked(data);
    } else {
        // 取消选中
        cancelChecked(data);
    }
}

/**
 * 取消复选框
 * 思路：
 * 1. 当前点击的 currentItem 需要取消
 * 2. currentItem 下所有的 children 都需要取消
 * 3. 判断 currentItem 所有的兄弟是否都取消，如果都取消了，父级才取消，如果兄弟有一个没有取消，父级也不取消
 */

const cancelChecked = (currentItem: MenuItem) => {

    const cancelChildChecked = (currentItem: MenuItem) => {
        if (currentItem.children) {
            currentItem.children.forEach(childItem => {
                treeRef.value!.setChecked(childItem._id, false, false);
                cancelChildChecked(childItem);
            })
        }
    }

    const cancelParentChecked = (currentItem: MenuItem) => {
        // 目前所有选中的 key
        const checkedKeys = treeRef.value!.getCheckedKeys();
        const parentItem = findItemById(currentItem.pid);
        if (parentItem) {
            // 判断当前父数据的子数据（不包含孙子）是否全部取消
            const isChecked = parentItem?.children?.some(child => checkedKeys.includes(child._id));
            if (!isChecked) {
                // 取消父级的勾选
                treeRef.value!.setChecked(parentItem._id, false, false);
                cancelParentChecked(parentItem);
            }
        }
    }

    cancelChildChecked(currentItem);
    cancelParentChecked(currentItem)
}



/**
* 选中复选框
* 思路：
* 1. 当前点击的 currentItem 需要选中
* 2. currentItem 下所有的 children 都需要选中
* 3. currentItem 的么一层父级都需要选中
*/

const setChecked = (currentItem: MenuItem) => {
    // 让当前选中数据的所有子数据全部选中
    const setChildChecked = (currentItem: MenuItem) => {
        if (currentItem.children) {
            currentItem.children.forEach(childItem => {
                treeRef.value!.setChecked(childItem._id, true, true);
                setChildChecked(childItem);
            })
        }
    }
    // 让当前选中数据的所有父数据全部选中
    const setParentChecked = (currentItem: MenuItem) => {
        if (currentItem.pid != '0') {
            treeRef.value!.setChecked(currentItem.pid, true, true);
            // 查找 currentItem.pid 对应的完整对象
            const parentItem = findItemById(currentItem.pid, data);
            if (parentItem) {
                setParentChecked(parentItem);
            }
        }
    }

    setChildChecked(currentItem);
    setParentChecked(currentItem);
}

const findItemById = (
    _id: string,
    targetArray: MenuItem[] = data
): MenuItem | undefined => {
    for (let item of targetArray) {
        if (item._id == _id) {
            return item;
        }
        if (item.children) {
            const currentItem = findItemById(_id, item.children);
            if (currentItem) {
                return currentItem;
            }
        }
    }
}

const getCheckedKeys = () => {
    return treeRef.value!.getCheckedKeys();
}

const setCheckedKeys = (keys: string[]) => {
    if (keys?.length == 0) {
        treeRef.value!.setCheckedKeys([]);
    } else {
        keys.forEach((key: string) => {
            treeRef.value!.setChecked(key, true, true)
        })
    }
}

defineExpose({
    getCheckedKeys,
    setCheckedKeys
})

</script>

<style scoped></style>